package com.gitee.feizns.quickstart.mybatis.flex.query;

import com.gitee.feizns.dynamic.reflect.Constructors;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.core.util.LambdaGetter;
import com.mybatisflex.core.util.LambdaUtil;
import com.mybatisflex.core.util.Reflectors;
import lombok.SneakyThrows;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 关系
 * @author feizns
 * @since 2025/8/8
 */
public interface Relationships {

    /**
     * 添加关系
     * @param mainField 主字段
     * @param subField  子字段
     * @param id       身份证
     * @param objectIds 对象 ID
     */
    @SneakyThrows
    @SuppressWarnings("unchecked")
    static <T> int add(LambdaGetter<T> mainField, LambdaGetter<T> subField, Object id, Object... objectIds) {
        Class<T> entityClass = getEntityClass(mainField, subField);
        List<T> ts = create(mainField, subField, id, objectIds);
        List<Object> subIds = subIds(mainField, id, subField, Object.class);
        Set<Object> subIdsSet = new HashSet<>(subIds);
        ts = ts.stream().filter(entity -> !subIdsSet.contains(subField.get(entity))).collect(Collectors.toList());
        return QueryChain.of(entityClass).baseMapper().insertBatch(ts);
    }

    /**
     * 删除指定关系
     * @param mainField 主字段
     * @param subField  子字段
     * @param id        编号
     * @param objectIds 对象 ID
     * @return boolean
     */
    @SneakyThrows
    @SuppressWarnings("unchecked")
    static <T> boolean delete(LambdaGetter<T> mainField, LambdaGetter<T> subField, Object id, Object... objectIds) {
        Class<T> entityClass = getEntityClass(mainField, subField);
        UpdateChain<T> eq = UpdateChain.of(entityClass).eq(mainField, id);
        if ( objectIds.length == 1 )
            eq.eq(subField, objectIds[0]);
        else if ( objectIds.length > 1 )
            eq.in(subField, objectIds);
        return eq.remove();
    }

    /**
     * 列表
     * @param field 田
     * @param value 价值
     * @return {@link List }<{@link T }>
     */
    @SuppressWarnings("unchecked")
    static <T> List<T> list(LambdaGetter<T> field, Object value) {
        Class<T> entityClass = getEntityClass(field);
        return QueryChain.of(entityClass).eq(field, value).list();
    }

    /**
     * 清空指定字段为指定值的关系
     * @param field 田
     * @param value 价值
     */
    @SuppressWarnings("unchecked")
    static <T> boolean clear(LambdaGetter<T> field, Object value) {
        Class<T> entityClass = getEntityClass(field);
        return UpdateChain.of(entityClass).eq(field, value).remove();
    }

    /**
     * 子 ID
     * @param field  田
     * @param value  价值
     * @param asType 作为类型
     * @return {@link List }<{@link R }>
     */
    @SuppressWarnings("unchecked")
    static <T, R> List<R> subIds(LambdaGetter<T> field, Object value, LambdaGetter<T> subIdField, Class<R> asType) {
        Class<T> entityClass = getEntityClass(field);
        return QueryChain.of(entityClass).eq(field, value).select(subIdField).objListAs(asType);
    }

    /**
     * 重置关系
     * @param mainField 主字段
     * @param subField  子字段
     * @param id        编号
     * @param objectIds 对象 ID
     * @return boolean
     */
    static <T> int reset(LambdaGetter<T> mainField, LambdaGetter<T> subField, Object id, Object...  objectIds) {
        //尽可能保留原有关联（避免数据丢失）
        return Db.txWithResult(() -> {
            //数据库中现在保留的关联
            List<Object> subIds = subIds(mainField, id, subField, Object.class);
            Set<Object> subIdsSet = new HashSet<>(subIds);
            //本次期望重置的关联
            List<Object> newSubIds = new ArrayList<>(Arrays.asList(objectIds));
            Set<Object> newSubIdsSet = new HashSet<>(newSubIds);
            //筛选需删除的关系
            List<Object> deleteSubIds = subIds.stream().filter(subId -> !newSubIdsSet.contains(subId)).collect(Collectors.toList());
            if ( !CollectionUtils.isEmpty(deleteSubIds) )
                delete(mainField, subField, id, deleteSubIds.toArray());
            //筛选需添加的关系
            List<Object> addSubIds = newSubIds.stream().filter(subId -> !subIdsSet.contains(subId)).collect(Collectors.toList());
            if ( !CollectionUtils.isEmpty(addSubIds) )
                return add(mainField, subField, id, addSubIds.toArray());
            return 0;
        });
    }

    /**
     * 存在
     * @param mainField 主字段
     * @param subField  子字段
     * @param mainId    主要编号
     * @param subIds     子编号
     * @return boolean
     */
    @SuppressWarnings("unchecked")
    static <T> boolean exists(LambdaGetter<T> mainField, LambdaGetter<T> subField, Object mainId, Object... subIds) {
        Class<T> entityClass = getEntityClass(mainField, subField);
        QueryChain<T> eq = QueryChain.of(entityClass).eq(mainField, mainId);
        if ( subIds.length == 1 )
            eq.eq(subField, subIds[0]);
        else if ( subIds.length > 1 )
            eq.in(subField, subIds);
        return eq.exists();
    }

    /**
     * 计数
     * @param mainField 主字段
     * @param value     价值
     * @return long
     */
    @SuppressWarnings("unchecked")
    static <T> long count(LambdaGetter<T> mainField, Object value) {
        Class<T> entityClass = getEntityClass(mainField);
        return QueryChain.of(entityClass).eq(mainField, value).count();
    }

    /**
     * 创造
     * @param mainField 主字段
     * @param subField  子字段
     * @param mainId    main编号
     * @param subId     子编号
     * @return {@link T }
     */
    @SneakyThrows
    @SuppressWarnings("unchecked")
    static <T> T create(LambdaGetter<T> mainField, LambdaGetter<T> subField, Object mainId, Object subId) {
        Class<T> entityClass = getEntityClass(mainField, subField);
        T instance = Constructors.newInstance(entityClass);
        String mainFieldName = LambdaUtil.getFieldName(mainField);
        String subFieldName = LambdaUtil.getFieldName(subField);
        Reflectors.of(entityClass).getSetInvoker(mainFieldName).invoke(instance, new Object[]{ mainId });
        Reflectors.of(entityClass).getSetInvoker(subFieldName).invoke(instance, new Object[]{ subId });
        return instance;
    }

    /**
     * 创造
     * @param mainField 主字段
     * @param subField  子字段
     * @param mainId    main编号
     * @param subIds    子 ID
     * @return {@link T }
     */
    static <T> List<T> create(LambdaGetter<T> mainField, LambdaGetter<T> subField, Object mainId, Object... subIds) {
        return Arrays.stream(subIds).map(subId -> create(mainField, subField, mainId, subId)).collect(Collectors.toList());
    }

    /**
     * 获取实体类
     * @param getters 属性
     * @return {@link Class }<{@link T }>
     */
    @SuppressWarnings("unchecked")
    static <T> Class<T> getEntityClass(LambdaGetter<T>... getters) {
        Class<T> entityClass = null;
        for ( LambdaGetter<T> getter : getters ) {
            Class<T> tmp = (Class<T>) LambdaUtil.getImplClass(getter);
            if ( entityClass != null && tmp != entityClass )
                throw new IllegalArgumentException("主从关系的实体类必须一致.");
            entityClass = tmp;
        }
        return entityClass;
    }

}
